#include <timberyard/threadpool.h>

namespace Timberyard {

ThreadPool::ThreadPool(unsigned int min, unsigned int max, unsigned int idle)
	: m_total(0), m_min(min), m_max( (max==0) ? 0 : (max<min?min:max) ), m_max_idle(idle), m_idle(0), m_queue(), m_mutex() {
	Tidy();
}

void ThreadPool::Tidy() {
	boost::mutex::scoped_lock lock(m_mutex);
	while (((m_max==0) || (m_total<m_max)) && (m_idle < m_max_idle-1)) {
		// one less, as the sensible thing to do would be use this pool to tidy itself
		this->AddThread();
	}
}

void ThreadPool::AddThread() {
	++m_total;
	++m_idle;
	new boost::thread(std::tr1::bind(&ThreadPool::Run,this));
}

void ThreadPool::Exec(std::tr1::function<void ()> fn) {
	m_queue.Push(fn);
	boost::mutex::scoped_lock lock(m_mutex);
	if ((m_idle<m_queue.size())&&(m_total<m_max)) AddThread();
}

bool ThreadPool::TooMany() {
	boost::mutex::scoped_lock lock(m_mutex);
	return (m_idle>m_max_idle) && (m_total>m_min);
}

void ThreadPool::Run() {

	while (!TooMany()) {
		std::tr1::function<void ()> fn=m_queue.Pop();
		try {
			{ // lock
				boost::mutex::scoped_lock lock(m_mutex);
				--m_idle;
			} // unlock
			fn();
			{ // lock
				boost::mutex::scoped_lock lock(m_mutex);
				++m_idle;
			} // unlock
		} catch (...) {
			// TODO: what?
		}
	}

	boost::mutex::scoped_lock lock(m_mutex);
	--m_idle;
}

} // namespace Timberyard
